package engine;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

import engine.individuals.Individual;
import engine.individuals.util.IndividualsComparator;

public class BoaAlgorithm<T extends Individual<?>> extends Algorithm<T> {

	private static final Logger logger = Logger.getLogger(BoaAlgorithm.class
			.getCanonicalName());
	
	private int chromosomeSize;

	public BoaAlgorithm(BoaPopulation<T> population, int chromosomeSize) {
		super(population);
		this.chromosomeSize = chromosomeSize;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see engine.Algorithm#run()
	 */
	@Override
	public void run() {

		List<Population<T>> populations = new ArrayList<Population<T>>(
				getOperators().size());

		while (true) {

			populations.clear();

			for (Operator<T> operator : getOperators()) {

				if (this.isFinished()) {
					return;
				}

				// logger.severe(getPopulation().toString());

				logger.warning("Applying operator " + operator.getClass().getName());

				Population<T> populationToCast = getPopulation();
				populations.add(populationToCast);
				if (operator instanceof BoaOperator) {
					BoaOperator<T> boaOperator = (BoaOperator<T>) operator;

					BoaPopulation<T> boaPopulation = null;
					if (!(populationToCast instanceof BoaPopulation)) {
						boaPopulation = new BoaPopulation<T>(populationToCast
								.getIndividuals(), chromosomeSize);
					} else {
						boaPopulation = (BoaPopulation<T>) populationToCast;
					}

					setPopulation(boaOperator.apply(boaPopulation, populations));
				} else {
					setPopulation(operator.apply(populationToCast));
				}
			}
		}
	}

	public T getBest(ObjectiveFunction<T> objectiveFunction) {
		
		return Collections.max(getPopulation().getIndividuals(),
				new IndividualsComparator<T>(objectiveFunction));
	}

	public BoaPopulation<T> getSortedPopulation(
			ObjectiveFunction<T> objectiveFunction) {
		
		Collections.sort(getPopulation().getIndividuals(),
				new IndividualsComparator<T>(objectiveFunction));
		
		return new BoaPopulation<T>(getPopulation().getIndividuals(), chromosomeSize);
	}
}
